package org.ccccye.distributedlocks.zookeeper;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.utils.CloseableUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class ZookeeperLock {
    @Value("${zookeeper.connect}")
    private String connectString;

//    @Value("${zookeeper.lock.path}")
    private String lockPath = "/distributed-lock";

    CuratorFramework client1;
    CuratorFramework client2;

    @Before
    public void init(){
        connectString = "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183";
        RetryPolicy retry = new ExponentialBackoffRetry(1000, 3);
        client1 = CuratorFrameworkFactory.newClient(connectString, 60000, 15000, retry);
        client2 = CuratorFrameworkFactory.newClient(connectString, 60000, 15000, retry);

        client1.start();
        client2.start();
    }

    @After
    public void close() {
        CloseableUtils.closeQuietly(client1);
        CloseableUtils.closeQuietly(client2);
    }

    @Test
    public void sharedReentrantLock() throws Exception {
        InterProcessLock lock1 = new InterProcessMutex(client1, lockPath);
        InterProcessLock lock2 = new InterProcessMutex(client1, lockPath);

        lock1.acquire();
        try {
            lock1.acquire();
            try {
                Assert.assertFalse(lock2.acquire(2, TimeUnit.SECONDS));
            }finally {
                lock1.release();
            }
        }finally {
            lock1.release();
        }

        Assert.assertTrue(lock2.acquire(2, TimeUnit.SECONDS));
        lock2.release();
    }
}
